""" DigitalICS: mobile data collection tool to complete surveys with integrated multimedia

    Copyright (C) 2009. Yael Schwartzman  

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>
    
    Contact information: Yael Schwartzman -  yaelsf@gmail.com
    """

from api.constants import Constants
from api.prompt import Prompt
from api.fexplorer import FExplorer
from api.logger import logger
import os.path as path
import os,time
try: import e32
except:import view.pseudoe32 as e32

from api.lang import Lang,Properties
p = Properties()
l = Lang(p.LANGUAGE)


#TODO: IN PROCESS output
#TODO: allow to define a default value in the form 
#TODO: MAYBE erase the audio and re-record instead of appending
#TODO: default the date to today
#TODO: when selecting community give a chance to do a new one (same for producer)


class Form:
    """ Form model """
    
    def __init__(self, id =None,id_type='INTEGER'):
        self.data = {}
        self.prompts = {}
        self.prompt_order = []
        self.id = id
        self.c = Constants()
        self.fexplorer = FExplorer()
        self.id_type = id_type
        
        self.save_folder =  self.fexplorer.get_save_folder()
        self.municipio = None
        self.localidad =None
        self.producer= None
        self.community = None
        self.num_parcels = None
        self.module = None # Python module that contains this form's definition
        self.name ="" # Form name
    
    
    def set_name(self,name):
        self.name = name
    
    def get_name(self):
        return  self.name

    def set_module(self,module):
        self.module = module
    
    def get_module(self):
        return  self.module

    def has_prompt(self,id):
        return self.prompt_order.__contains__(id) 
    
    def get_prompt_index(self,prompt):
        try: 
            return self.prompt_order.index(prompt.get_id())
        except:
            print "%s not in list " % prompt.get_id()
            return 0
        
    def set_producer_id(self,id):
        self.producer = id
        if self.id == p.MASTER_FORM:
            self.update_data_value(l.PRODUCER,id)
        
    def get_producer_id(self):
        return self.producer
    
    def set_community_id(self,id):
        self.community = id
        if self.id == p.MASTER_FORM:
            self.update_data_value(l.ORGANIZATION,id)
    
    def set_municipio_id(self,id):
        self.municipio = id
        if self.id == p.MASTER_FORM:
            self.update_data_value('Municipio',id)
            
    def set_localidad_id(self,id):
        self.localidad = id
        if self.id == p.MASTER_FORM:
            self.update_data_value('Localidad',id)

    def get_municipio_id(self):
        return self.municipio
    
    def get_localidad_id(self):
        return self.localidad 
                    
    def set_num_parcels(self,num_parcels):
        self.num_parcels = num_parcels
                
    def get_num_parcels(self):
        return self.num_parcels 
        
    def get_community_id(self):
        return self.community 
    
    
    def set_id(self, id):
        """ set form name/id"""
        self.id = id
        
    def get_id(self):
        """ set form name/id"""
        return u'%s'% self.id 
        
    def clear_values(self):
        for key in self.data:
            self.data[key] = None
        self.producer = None
        self.community = None
        self.localidad = None
        self.municipio = None
        
    def add_data(self, data):
        """ add a form variable"""
        if not self.data.has_key(data):
            self.data[data] = None 
    
    def add_repeated_prompt(self,original_name,offset,prompt):
        """ For the questions that need multiple answers (e.g. one per farm)"""
        index = self.prompt_order.index(original_name)
        id = prompt.get_id()
        self.prompt_order.insert(index+offset+1,id)
        self.prompts[id] = prompt
    
    def remove_prompt(self,prompt_id,data_name):
        self.data.pop(data_name)
        self.prompt_order.remove(prompt_id)
        self.prompts.pop(prompt_id)    
        
        
    def remove_prompts(self,parent_id,num_prompts):
        """remove repeated prompts""" 
        parent_prompt = self.get_prompt(name = parent_id)
        data = parent_prompt.get_data()
        for i in range(1,num_prompts+1):
            repeated_id = self.get_repeated_id(parent_id,i)
            repeated_data = self.get_repeated_data(data,i)
            self.remove_prompt(repeated_id,repeated_data)
            
    def get_existing_repeated_prompts(self,id):
        i = 0
        for prompt in self.prompt_order:
            if prompt.startswith(id):
                if len(prompt) > len(id):
                    i+=1
        return i
    
    
    def get_repeated_label(self,label,repeat):
        return "%s - %s" % (repeat,label)
    
    def get_repeated_id(self,id,repeat): 
        return "%s_%s" % (id,repeat)
    
    def get_repeated_data(self,data,repeat):
        return "%s_%s"% (data,repeat)
        
    def add_data_value(self,data,value):
        self.data[data] = value
    
    def add_mult_data(self,data_list):
        for item in data_list:
            self.data[item] = ""
             
    def add_prompt(self,id, data ,label,input_type, default = None,hint =None,options =None, return_type = None, relevance = None, module = None,method = None, media_file = None, audio = None, repeat = None,output = None, breach = None, special_breach = None):                    
        """ add this prompt to the form"""
        self.prompts[id] = Prompt(id , data ,label ,input_type , default =default,hint = hint, 
                                  options =options, return_type=return_type, relevance=relevance, 
                                  module=module,method=method,media_file=media_file, audio=audio,
                                  repeat=repeat,output=output,breach=breach,special_breach=special_breach) 
        self.prompt_order.append(id)
    
    def get_prompt(self,index = None, name = None):
        if index is None:
            if name is None:
                raise "you need to get a prompt using either a name or an index"
            else:
                return self.prompts[name]
        else:
            prompt_id  =  self.prompt_order[index]
            return self.prompts[prompt_id]
    
    def get_prompts(self):
        return [u'%s'% item for item in self.prompt_order] 
    
    def get_prompt_order(self):
        return self.prompt_order
    
    def update_data_value(self,data,value):
        #TODO : fix this ts1 ts2 thing
        if data == "ts1" or data == "ts2":
            if self.data[data] == "" : 
                self.data[data] = value
            else: 
                self.data[data] = "%s,%s"% (self.data[data],value)
        else: 
            self.data[data] = value
        
    def size(self):
        return len(self.prompt_order)

    def get_data(self):
        return [(f,self.data[f]) for f in self.data.keys()]

    def prompt_is_relevant(self,prompt):
        """  If this prompt should be prompted based on previous responses"""
        relevance = prompt.get_relevance()
        if relevance is None:
            return True
        for prompt_id in relevance.keys():
            value = relevance[prompt_id]
            parent_prompt = self.prompts[prompt_id]
            existing_val = self.get_data_rep(prompt = parent_prompt) 
            if type(value) == list:
                existing_val = existing_val.split(',')
                comp = eval('%s.%s(%s)' %(existing_val,value[0],value[1]))
            else:
                if type(existing_val) == unicode or type(existing_val) == str: 
                    existing_val = "'%s'" % existing_val
                comp = eval("%s %s " %(existing_val, value)) 
            if not comp:
                return False
        return True
    
    def get_data_value(self,data_name = None, id = None):
        if data_name is None:
            if id is None:
                raise "Getting a data value you must either enter a data_name or an id"
            else:
                data_name = self.get_data_name_for_prompt(id)
        if not self.data.has_key(data_name):
            pass
        if data_name in self.data.keys():
            return self.data[data_name]
        else:
            return None
    
    def get_ids_and_values(self):
        items = []
        for prompt_id in self.prompt_order:
            prompt = self.get_prompt(name = prompt_id)
            data_name = prompt.get_data()
            id = prompt.get_id()
            value = self.get_data_value(data_name = data_name)
            if value != "" :
                data_rep = self.get_data_rep(prompt = prompt)
                items.append(u"%s: %s" % (id, data_rep))
                
            else:
                items.append(u"%s: %s" % (id, ""))
            
        return items
        
    def get_data_and_values(self):
        items = []
        for prompt_id in self.prompt_order:
            prompt = self.get_prompt(name = prompt_id)
            data_name = prompt.get_data()
            value = self.get_data_value(data_name = data_name)
            if value != "" :
                if prompt.relevance is None:
                    data_rep = self.get_data_rep(prompt = prompt, value = value)
                    items.append(u"%s: %s" % (data_name, data_rep))
                elif self.prompt_is_relevant(prompt):
                    data_rep = self.get_data_rep(prompt = prompt,value = value)
                    items.append(u"%s: %s" % (data_name, data_rep))
            else:
                items.append(u"%s: %s" % (data_name, ""))
            
        return items
        
    def get_data_rep(self,prompt = None, id = None, value = None):
        """  output representation for the data for the form view"""
        if prompt is None:
            if id is None:
                raise Exception("get_data_rep should either have prompt or id")
            else:
                prompt = self.prompts[id]
        
        if value is None:
            value = self.get_data_value(data_name = prompt.get_data()) 
        return_type = prompt.get_return_type()
        input_type = prompt.get_input_type()
        
        if value is None:
            return "" 
        if type(value) == str:
            if value.strip() == "":
                return ""
        
        if input_type == self.c.INPUT:
            if return_type == self.c.RETURN_DATE: 
                time_tuple = time.gmtime(value)
                return time.strftime("%Y-%m-%d",time_tuple)   
            elif type(value) == str: 
                return value.strip()
            else:
                return value
        elif input_type == self.c.SELECT: 
             options = prompt.get_options()
             
             try: return ",".join([options[i] for i in value])
             except:return value
                 
        else:
            return value
    
    def get_data_name_for_prompt(self,key):
        return self.prompts[key].get_data()
    
    def has_no_identification(self):
        if self.id_type == "LIST":
            return self.producer is None or self.community is None
        else:
            return self.producer is None or self.community is None or self.municipio is None or self.localidad is None
     
    
    def has_everything_but_producer(self):
        if self.id_type == "LIST":
            return self.producer is None and self.community is not None
        else:
            return self.producer is None and self.community is not None and self.municipio is not None and self.localidad is  not None

                 
    def save_form(self):
        #print "id %s" %self.id_type
        if self.id_type == 'LIST':
            if self.producer and self.community and self.id:
                self.fexplorer.save_common_ids(self.community)
                form_dirs = path.join(self.save_folder,"%s\\%s" % (self.community,self.producer))
                if not os.path.exists(form_dirs) and form_dirs.find('None')==-1:
                    try: os.makedirs(form_dirs,mode=0777)
                    except: 
                        print "could not make dir %s "% form_dirs
                        return False
        else:
            if not (self.producer is None or self.community is None \
                    or self.municipio is None or self.localidad is None or self.id is None):
                self.fexplorer.save_common_ids(self.community,self.municipio,self.localidad)
                form_dirs = path.join(self.save_folder,"%s\\%s\\%s\\%s" % (self.community,self.municipio,self.localidad,self.producer))
                #print "form_dirs %s" % form_dirs
                if not os.path.exists(form_dirs) and form_dirs.find('None')==-1:
                    try: os.makedirs(form_dirs,mode=0777)
                    except: 
                        print "could not make dir %s "% form_dirs
                        return False                     
        file = open(path.join(form_dirs,"%s.form" %self.module),'w')        
        for prompt_id in self.prompt_order:
            prompt = self.get_prompt(name = prompt_id)
            data_name = prompt.get_data()
            value = self.get_data_value(data_name = data_name)    
            file.write("%s: %s \n" % (data_name,value))
        timestamps = self.get_timestamps()
        for i in timestamps: 
            file.write("%s \n"% i) 
        file.close()
        return True
            


    def load_form(self, community = None,producer = None, id = None, save_folder = None,municipio=None,localidad=None):
        if self.id_type == 'LIST':
            if not producer is None and not community is None and not id is None:
                # if loading new form
                return self._load_form(community=community,producer=producer,id=id,save_folder=save_folder)
            elif not self.producer is None and not self.community is None and not self.module is None:
                # if reloading this form
                return self._load_form(community=self.community,producer=self.producer,id=self.module,save_folder=save_folder)
            else:
                return False
        else:
            if not( producer is None or community is None or id is None \
                or localidad is None or municipio is None):
                #print "not self"
                return self._load_form(community=community,municipio = municipio, localidad = localidad,producer=producer,id=id,save_folder=save_folder)
            elif not self.producer is None and not self.municipio is None and \
                not self.localidad is None and  not self.community is None and not self.module is None:
                #print "self is not none"
                return self._load_form(community=self.community,municipio =self.municipio,localidad=self.localidad,producer=self.producer,id=self.module,save_folder =save_folder)
            else:
                return False

    def _load_form(self,community=None,producer=None,id=None,save_folder=None,municipio=None,localidad= None):
        
        self.community = community
        self.producer = producer
        self.module = id
        if save_folder is not None:
            self.save_folder = save_folder
        
        if self.id_type=='INTEGER':
            self.municipio= municipio
            self.localidad = localidad
            filename = path.join(self.save_folder,"%s/%s/%s/%s/%s.form" %(community,municipio,localidad,producer,id))
        else:
            filename = path.join(self.save_folder,"%s/%s/%s.form" %(community,producer,id))
        
        if id == p.MASTER_FORM:
            return self.update_main_form() 
        try: 
            file = open(filename,"r")
        except: 
            return False
        for line in file:
            if len(line.split(":")) >1 :
                key,data = line.split(":",1) 
                data = data[:-1]
                try:
                    data = eval(data)
                except:
                    data = data
                self.update_data_value(key,data) # to take the \n out 
        file.close()
        return True

    def update_with_common_ids(self):
        if self.id_type == 'LIST':
            self.community = self.fexplorer.get_common_ids()
            self.update_data_value(l.ORGANIZATION,self.community)
        else:
            self.community,self.municipio,self.localidad = self.fexplorer.get_common_ids()
            self.update_data_value(l.ORGANIZATION,self.community)
            self.update_data_value('Municipio',self.municipio)
            self.update_data_value('Localidad',self.localidad)
        
        
    def update_main_form(self):     
        self.update_data_value(l.ORGANIZATION,self.community)
        self.update_data_value(l.PRODUCER,self.producer)
        if self.id_type == 'INTEGER':
            self.update_data_value('Municipio',self.municipio)
            self.update_data_value('Localidad',self.localidad)
            
        
        completed_sections = self.get_completed_sections()
        for section in completed_sections: 
            self.update_data_value(section.replace('.form',''),l.COMPLETED )
        
        return self.save_form()
        
    def get_completed_sections(self):
        if self.id_type == "LIST":
            form_list = self.fexplorer.get_form_list(self.community,
                                                 self.producer)
        else:
            form_list = self.fexplorer.get_form_list(community =self.community,
                                                 producer = self.producer,
                                                 municipio = self.municipio,
                                                 localidad = self.localidad)
        return form_list
    
    def get_index_for_prompt_id(self,prompt_id):
        if prompt_id in self.prompt_order:
            ind = self.prompt_order.index(prompt_id)
        else:
            logger.log_error("could not get prompt %s " % prompt_id)
            return -1
        
        return ind
    
    def get_timestamps(self):
        return ["ts1: %s"% self.get_data_value("ts1"),"ts2: %s"% self.get_data_value("ts2")]
    
    def get_audio_and_pictures(self,path): 
         media_dir = []
         if os.path.exists("%s\\audio"%path):
             media_dir.extend( os.listdir(os.path.join(path,"audio")))
         if os.path.exists("%s\\pics"%path):
             pic_dir = os.listdir(os.path.join(path,"pics"))
             for pic in pic_dir:
                 if pic.endswith(".jpg"):
                    media_dir.append(pic) 
         
         return media_dir
     
     

    def get_media_path(self):
        """ this is where the picture or recording gets saved"""      
    
        commty =self.get_community_id()
        prod =self.get_producer_id()
        if self.id_type == "INTEGER":
            muni =self.get_municipio_id()
            loc =self.get_localidad_id()
            path = (commty,muni,loc,prod)
        else:
            path = (commty,prod)
        
        return tuple(["%s"%i for i in path])
    
    def make_media_path(self,community = None,municipio=None,localidad=None,producer=None):   
         items = ["%s" % community,"%s" % producer]
         if self.id_type == "INTEGER": items.extend(["%s" % municipio, "%s" % localidad])
         for item in items:
             if item == 'None':
                 return False
         if self.id_type == "INTEGER":
             media_dirs  = os.path.join(self.save_folder,"%s\\%s\\%s\\%s" % (community,municipio,localidad,producer))
         else:
             media_dirs  = os.path.join(self.save_folder,"%s\\%s" % (community,producer))

         if not os.path.exists(media_dirs): 
                    os.makedirs('%s\\pics' %media_dirs,mode=0777)
                    os.makedirs('%s\\audio' %media_dirs,mode=0777)
         return media_dirs

    def get_inspector(self):
        exec("from forms.%(is)s import %(is)s" % ({'is': p.INSPECTOR_FORM}))
        inspector_form = eval(p.INSPECTOR_FORM)
        if self.id_type == 'INTEGER':
            secc_1 = inspector_form(community = self.community,producer = self.producer,municipio = self.municipio,localidad =self.localidad)
        else:
            secc_1 = inspector_form(community = self.community,producer = self.producer)
        if secc_1.load_form():     
            return secc_1.get_data_value(data_name = l.INSPECTOR)
        else:
            return 0
        
